home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Expert
/
Windows Expert.iso
/
others
/
ole_101.zip
/
PATRON.ZIP
/
OLEOBJ.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-13
|
21KB
|
801 lines
/*
* OLEOBJ.C
*
* Constructor and Destructor for the OBJECT structure. Since this is
* not a placeholder for a real OLE structure, there is no VTBL and
* so there are no standard methods for it.
*
* Copyright(c) Microsoft Corp. 1992 All Rights Reserved
*
*/
#include <windows.h>
#include <ole.h>
#include "oclient.h"
/*
* PObjectAllocate
*
* Purpose:
* Allocates an OBJECT structure. This function only creates the
* structure and inserts it into the owner's list.
*
* Parameters:
* pfSuccess LPBOOL indicating if the initialization succeeded. If
* this function returns non-NULL, but *pfSuccess==FALSE,
* the caller must call the destructor function.
* pDoc LPDOCUMENT to the owner of this object, which contains
* pObjLast where we attach ourself, and a pszData1 scratch
* area.
*
* Return Value:
* LPOBJECT Pointer to the allocated OBJECT if successful, NULL
* if the allocation failed or a parameter is invalid.
*/
LPOBJECT FAR PASCAL PObjectAllocate(LPBOOL pfSuccess, LPDOCUMENT pDoc)
{
HANDLE hMem;
LPOBJECT pObj;
if (NULL==pfSuccess)
return NULL;
*pfSuccess=FALSE;
if (NULL==pDoc)
return NULL;
hMem=LocalAlloc(LPTR, CBOBJECT);
if (NULL==hMem)
return FALSE;
//All fields are initially NULL from the LocalAlloc.
pObj=(LPOBJECT)(PSTR)hMem;
//Must set VTBL since we may pass this to an OLE function.
pObj->pvt=pDoc->pvt;
//Set the previous and next pointers for this object in the list.
if (NULL==pDoc->pObjFirst)
pDoc->pObjFirst=pObj;
pObj->pPrev=pDoc->pObjLast;
if (NULL!=pObj->pPrev)
{
pObj->pNext=pObj->pPrev->pNext;
pObj->pPrev->pNext=pObj;
}
else
pObj->pNext=NULL;
if (NULL!=pObj->pNext)
pObj->pNext->pPrev=pObj;
pDoc->pObjLast=pObj;
//Honor thy parent.
pObj->pDoc=pDoc;
//We're all done!
pDoc->cObjects++;
*pfSuccess=TRUE;
return pObj;
}
/*
* PObjectInitialize
*
* Purpose:
* Initializes an OBJECT structure and assumes that the pObj field
* in the structure already contains a valid OLEOBJECT pointer.
*
* Parameters:
* pObj LPOBJECT to the object to initialize.
* pDoc LPDOCUMENT to the owner of this object.
*
* Return Value:
* LPOBJECT pObj if successful, NULL otherwise.
*/
LPOBJECT FAR PASCAL PObjectInitialize(LPOBJECT pObj, LPDOCUMENT pDoc)
{
WORD wTemp;
LPSTR pszT;
OLESTATUS os;
if (NULL==pObj || NULL==pDoc)
return NULL;
//Add this object's name as an ATOM
wTemp=CBSCRATCH;
os=OleQueryName(pObj->pObj, pDoc->pszData1, &wTemp);
if (OLE_OK!=os)
return NULL;
if (0!=pObj->aName)
DeleteAtom(pObj->aName);
pObj->aName=AddAtom(pDoc->pszData1);
//Get the type, OT_LINK, OT_EMBEDDED, or OT_STATIC
os=OleQueryType(pObj->pObj, &pObj->dwType);
if (OLE_OK!=os)
return NULL;
/*
* Set these names with OLECLI only for an *embedded* object. If
* you call this for a linked object you'll see OLE_ERROR_OBJECT.
*/
if (OT_EMBEDDED==pObj->dwType)
{
//pDoc has the document name.
GetAtomName(pDoc->aCaption, pDoc->pszData2, CBSCRATCH);
os=OleSetHostNames(pObj->pObj, pDoc->pszData2, pDoc->pszData1);
if (OLE_OK!=OsError(os, pDoc, pObj, TRUE))
return NULL;
}
//Get the type of link, if we are indeed linked
if (OT_LINK==pObj->dwType)
{
os=OleGetLinkUpdateOptions(pObj->pObj, &pObj->dwLink);
if (OLE_OK!=os)
return NULL;
//If we're linked, get the linked document name.
if (FALSE==FObjectDataGet(pObj, pDoc->cfObjectLink, pDoc->pszData1))
return NULL;
//Store the components of this linked item in ATOMS.
pszT=pDoc->pszData1;
if (0!=pObj->aClass)
DeleteAtom(pObj->aClass);
pObj->aClass=AddAtom(pszT); //Classname
pszT+=lstrlen(pszT)+1;
if (0!=pObj->aLink)
DeleteAtom(pObj->aLink);
pObj->aLink=AddAtom(pszT); //Link file
pszT+=lstrlen(pszT)+1;
if (0!=pObj->aSel)
DeleteAtom(pObj->aSel);
pObj->aSel=AddAtom(pszT); //Selection
}
return pObj;
}
/*
* PObjectFree
*
* Purpose:
* Frees all data in the OBJECT and frees the structure.
*
* Parameters:
* pDoc LPDOCUMENT containing first/last pointers that need
* to be managed.
* pObj LPOBJECT to the structure to free.
*
* Return Value:
* LPOBJECT NULL if the function succeeds, pObj otherwise
*/
LPOBJECT FAR PASCAL PObjectFree(LPDOCUMENT pDoc, LPOBJECT pObj)
{
LPOBJECT pPrev;
LPOBJECT pNext;
OLESTATUS os;
if (NULL==pObj)
return NULL;
if (NULL==LocalHandle((HANDLE)(DWORD)pObj))
return NULL;
pPrev=pObj->pPrev;
pNext=pObj->pNext;
if (NULL!=pObj->aSel)
DeleteAtom(pObj->aSel);
if (NULL!=pObj->aLink)
DeleteAtom(pObj->aLink);
if (NULL!=pObj->aClass)
DeleteAtom(pObj->aClass);
if (NULL!=pObj->aName)
DeleteAtom(pObj->aName);
//Free any cloned object we might be carrying.
if (NULL!=pObj->pObjUndo)
{
os=OleDelete(pObj->pObjUndo);
pObj->pObj=pObj->pObjUndo; //FOLEReleaseWait uses pObj->pObj
OsError(os, pDoc, pObj, TRUE);
}
//Free the structure.
if (NULL!=LocalFree((HANDLE)(DWORD)pObj))
return pObj;
//Remove this object from the list.
if (pDoc->pObjFirst==pObj)
pDoc->pObjFirst=pNext;
if (pDoc->pObjLast==pObj)
pDoc->pObjLast=pPrev;
if (NULL!=pPrev)
pPrev->pNext=pNext;
if (NULL!=pNext)
pNext->pPrev=pPrev;
pDoc->cObjects--;
return NULL;
}
/*
* FObjectsEnumerate
*
* Purpose:
* Enumerates all allocated OBJECT structures, passing them to
* a specified enumeration function given in pfn which should appear
* as:
* BOOL FAR PASCAL EnumFunc(LPDOCUMENT pDoc, LPOBJECT pObj)
*
* (EnumFunc can be any name). The return value of EnumFunc is
* TRUE to continue the enumeration, FALSE otherwise.
*
* This function provides a different enumeration method than OleEnumObjects
* since it contains the loop instead of embedding OleEnumObjects inside
* your own loop. The enumeration provided by this function is more
* consistent with other Windows Enum* functions.
*
* Parameters:
* pDoc LPDOCUMENT identifying the owner of the objects.
* pfn LPFNOBJECTENUM to the enumeration handler.
* dw DWORD containing extra data to pass to the enumeration
* function.
*
* Return Value:
* BOOL TRUE if ALL objects were enumerated, FALSE if the
*/
BOOL FAR PASCAL FObjectsEnumerate(LPDOCUMENT pDoc, LPFNOBJECTENUM pfn, DWORD dw)
{
LPOBJECT pObj;
pObj=pDoc->pObjFirst;
/*
* Note: If we didn't store a list of objects outselves, we could
* continually use OleEnumObjects. However, OleEnumObjects only
* returns an LPOLEOBJECT and we would not have OUR OBJECT structure,
* meaning we'd have to look it up in our own list anyway.
*/
while (NULL!=pObj)
{
if (!(*pfn)(pDoc, pObj, dw))
break;
pObj=pObj->pNext;
}
return (NULL==pObj);
}
/*
* FObjectPaint
*
* Purpose:
* Calls OleDraw for a specified object to draw the object ON THE SCREEN.
* If the object is open, it also paints the newly drawn object with a
* HS_BDIAGONAL hatch brush to show the open state.
*
* Parameters:
* hDC HDC on which to paint.
* pRect LPRECT giving area to paint.
* pOLEObj LPOLEOBJECT to the object to paint
*
* Return Value:
* BOOL TRUE if successful, FALSE otherwise.
*/
BOOL FAR PASCAL FObjectPaint(HDC hDC, LPRECT pRect, LPOBJECT pObj)
{
OLESTATUS os;
HBRUSH hBr, hBrT;
//Draw the object
os=OleDraw(pObj->pObj, hDC, pRect, NULL, NULL);
os=OsError(os, pObj->pDoc, pObj, TRUE);
if (OLE_OK!=os)
return FALSE;
//If this EMBEDDED object is open, patch a hatch over the image.
if (pObj->fOpen && OT_EMBEDDED==pObj->dwType)
{
hBr=CreateHatchBrush(HS_BDIAGONAL, GetSysColor(COLOR_HIGHLIGHT));
hBrT=SelectObject(hDC, hBr);
/*
* The 0x00A000C9L ROP code does an AND between the pattern and
* the destination; there is no standard definition for this
* ROP code, but it's exactly what we want to draw COLOR_HIGHTLIGHT
* lines across the object when it's open.
*/
PatBlt(hDC, pRect->left, pRect->top,
pRect->right-pRect->left, pRect->bottom-pRect->top, 0xA000C9L);
SelectObject(hDC, hBrT);
DeleteObject(hBr);
}
return TRUE;
}
/*
* FObjectRectSet
*
* Purpose:
* Provides the object with a screen-relative rectangle. The object
* itself assumes that the rectangle contains coordinates in units defined
* by the mapping mode in mm. The rectangle given here is sent to the
* OleSetBounds function for this object after which we call OleUpdate.
*
* Parameters:
* pDoc LPDOCUMENT containing OLE information.
* pObj LPOBEJCT to the object in which to store the handle.
* pRect LPRECT to the rectangle of the object in device units.
* mm WORD specifying the mapping mode of pRect.
*
* Return Value:
* BOOL TRUE the set succeeds, FALSE if OleSetBounds fails
* or if an invalid pointer is passed.
*/
BOOL FAR PASCAL FObjectRectSet(LPDOCUMENT pDoc, LPOBJECT pObj, LPRECT pRect, WORD mm)
{
OLESTATUS os;
if (NULL==pObj || NULL==pRect)
return FALSE;
RectConvertMappings(pRect, mm, MM_HIMETRIC);
os=OleSetBounds(pObj->pObj, pRect);
if (OLE_OK!=OsError(os, pDoc, pObj, TRUE))
return FALSE;
os=OleUpdate(pObj->pObj);
if (OLE_OK!=OsError(os, pDoc, pObj, TRUE))
return FALSE;
return TRUE;
}
/*
* FObjectRectGet
*
* Purpose:
* Retrieves the object's rectangle stored in the specified units.
*
* Parameters:
* pObj LPOBJECT to the object concerned.
* pRect LPRECT
* mm WORD mapping mode in which to retrieve coordinates.
*
* Return Value:
* BOOL TRUE if the function succeeds, FALSE otherwise.
*/
BOOL FAR PASCAL FObjectRectGet(LPOBJECT pObj, LPRECT pRect, WORD mm)
{
RECT rc;
OLESTATUS os;
if (NULL==pObj || NULL==pRect)
return FALSE;
os=OleQueryBounds(pObj->pObj, &rc);
//The most common error here is usually OLE_ERROR_BLANK.
if (OLE_OK!=os)
return FALSE;
RectConvertMappings(&rc, MM_HIMETRIC, mm);
CopyRect(pRect, &rc);
return TRUE;
}
/*
* FObjectDataGet
*
* Purpose:
* Calls OleGetData for a particular object to retrieve data
* in the specified format, either ObjectLink or OwnerLink.
* The contents are copied into a buffer pointed to by psz on which
* no length assumptions are made.
*
* Parameters:
* pObj LPOBJECT containing the OLEOBJECT from which to
* retrieve data.
* cf WORD specifying the ObjectLink or OwnerLink format.
* psz LPSTR pointer to buffer to store the string.
*
* Return Value:
* BOOL TRUE if the function succeeds, FALSE otherwise.
*/
BOOL FAR PASCAL FObjectDataGet(LPOBJECT pObj, WORD cf, LPSTR psz)
{
OLESTATUS os;
HANDLE hLink;
LPSTR pszLink;
WORD cch;
if (NULL==pObj || NULL==psz)
return FALSE;
//Get link data.
os=OleGetData(pObj->pObj, cf, &hLink);
if (OLE_OK!=os && OLE_WARN_DELETE_DATA!=os)
return FALSE;
pszLink=GlobalLock(hLink);
//Copy the link data to the buffer.
if (NULL!=pszLink)
{
//Copy three separate null-terminated strings.
lstrcpy(psz, pszLink);
cch=lstrlen(pszLink)+1;
lstrcpy(psz+cch, pszLink+cch);
cch+=lstrlen(pszLink+cch)+1;
lstrcpy(psz+cch, pszLink+cch);
//Add the final null-terminator.
cch+=lstrlen(pszLink+cch)+1;
*(psz+cch)=0;
}
GlobalUnlock(hLink);
if (OLE_WARN_DELETE_DATA==os)
GlobalFree(hLink);
if (NULL==pszLink)
return FALSE;
return TRUE;
}
/*
* FObjectDataSet
*
* Purpose:
* Calls OleSetData for a particular object to update data in the
* in the specified format, either ObjectLink or OwnerLink. The only
* changable field in the data is the document (2nd string) which
* is provided in pszDoc.
*
* FObjectDataSet passes the new data to OlsSetData and stores it
* in psz; no assumptions are made about the length of psz.
*
* Parameters:
* pDoc LPDOCUMENT containing OLE information.
* pObj LPOBJECT containing the OLEOBJECT to receive the
* new data.
* cf WORD specifying the ObjectLink or OwnerLink format.
* pszDoc LPSTR to the new link file
*
*
* Return Value:
* BOOL TRUE if the function worked, FALSE otherwise.
*
*/
BOOL FAR PASCAL FObjectDataSet(LPDOCUMENT pDoc, LPOBJECT pObj, WORD cf, LPSTR pszDoc)
{
HANDLE hMem;
LPSTR pszT;
OLESTATUS os;
if (NULL==pObj || NULL==pszDoc)
return FALSE;
//OleSetData requires a global handle to the data. Assume 1K is enough
hMem=GlobalAlloc(GHND | GMEM_DDESHARE, 1024);
if (NULL==hMem)
return FALSE;
pszT=GlobalLock(hMem);
/*
* Copy the Object/OwnerLink formats. Note that we similtaneously
* build the copy in psz and the new memory handle.
*/
//Copy the classname and point pszT to the document location.
pszT+=1+GetAtomName(pObj->aClass, pszT, 256);
//Copy the new filename and point to the selection location.
if (NULL!=pObj->aLink)
DeleteAtom(pObj->aLink);
pObj->aLink=AddAtom(pszDoc);
lstrcpy(pszT, pszDoc);
pszT+=lstrlen(pszT)+1;
//Copy the old selection data.
pszT+=1+GetAtomName(pObj->aSel, pszT, 512);
//Add the list terminator (second NULL)
*(pszT)=0;
GlobalUnlock(hMem);
//Update this data with OLE.
os=OleSetData(pObj->pObj, cf, hMem);
if (OLE_OK!=OsError(os, pDoc, pObj, TRUE))
return FALSE;
return TRUE;
}
/*
* FOLEReleaseWait
*
* Purpose:
* Enters a Peek/Translate/Dispatch message loop to process all messages
* to the application until one or all objects are released. This message
* processing is necessary beacuse OLECLI.DLL and OLESVR.DLL communicate
* with asynchronous DDE messages.
*
* The fWaitForAll flag indicates how to interpret the pv parameter.
*
* 1. If TRUE==fWaitForAll, then pv points to a CLIENT structure,
* and we loop until cWait is zero.
*
* 2. If FALSE==fWaitForAll, then pv points to an OLEOBJECT,
* so loop until OleQueryReleaseStatus returns something
* other than OLE_BUSY.
*
* Parameters:
* fWaitForAll BOOL indicating if pv is a CLIENT or OLEOBJECT,
* which defines how we terminate the loop.
* pDoc LPDOCUMENT containing OLE information, such as message
* procedures and the cWait counter.
* pObj LPOBJECT to the object to wait for if fWaitForAll is
* FALSE. Ignored if fWaitForAll is TRUE.
*
* Return Value:
* BOOL TRUE if we yielded, FALSE otherwise. For what it's worth.
*/
BOOL FAR PASCAL FOLEReleaseWait(BOOL fWaitForAll, LPDOCUMENT pDoc, LPOBJECT pObj)
{
BOOL fRet=FALSE;
MSG msg;
while (TRUE)
{
//Test terminating condition.
if (fWaitForAll)
{
if (0==pDoc->cWait)
break;
}
else
{
/*
* Depending on a flag change in the CallBack method is like
* handling an interrupt. We could call OleQueryReleaseStatus
* as well for a polling technique.
*/
if (pObj->fRelease)
break;
}
/*
* We use PeekMessage here to make a point about power
* management and ROM Windows--GetMessage, when there's
* no more messages, will correctly let the system go into
* a low-power idle state. PeekMessage by itself will not.
* If you do background processing in a PeekMessage loop like
* this, and there's no background processing to be done,
* then you MUST call WaitMessage to duplicate the idle
* state like GetMessage.
*/
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
{
/*
* We will not see WM_QUIT in the middle of the application
* since this application MUST call PostQuitMessage to get
* in the queue. Therefore we don't even worry about it.
*/
if (NULL!=pDoc->pfnMsgProc)
(*pDoc->pfnMsgProc)(&msg);
}
else
{
/*
* If the application has some background processing
* to do, perform a piece of it here. Otherwise make sure
* we somehow call WaitMessage to allow power-management
* functions to take effect. You don't want to mess with
* battery life, now do you?
*/
if (NULL==pDoc->pfnBackProc)
WaitMessage();
else
{
if (!(*pDoc->pfnBackProc)(&msg))
WaitMessage();
}
fRet=TRUE;
}
}
return fRet;
}
/*
* OsError
*
* Purpose:
* Provides a centralized error handler for OLE function calls, depending
* on the value in os:
*
* OLE_OK Return OLE_OK
* OLE_BUSY Display a message and return OLE_BUSY.
* Any OLE error Return that error.
* OLE_WAIT_FOR_RELEASE Call FOLEReleaseWait on the object if
* fWait is TRUE, then call OleQueryReleaseError
* for the return value. Otherwise increment
* pDoc->cWait.
*
* Parameters:
* os OLESTATUS error value to check.
* pDoc LPDOCUMENT containing OLE information.
* pObj LPOBJECT containing the object that we manipulated.
* fWait BOOL indicates if we are to wait for release on the
* object or increment a flag for later waiting.
*
* Return Value:
* OLESTATUS New error code depending on the original os.
*/
OLESTATUS FAR PASCAL OsError(OLESTATUS os, LPDOCUMENT pDoc, LPOBJECT pObj, BOOL fWait)
{
#ifdef DEBUG
OLE_RELEASE_METHOD orm;
char szMsg[128];
#endif
switch (os)
{
case OLE_OK:
break;
case OLE_BUSY:
MessageBox(pDoc->hWnd, PSZOLE(IDS_OBJECTBUSY),
PSZOLE(IDS_OLEERROR), MB_OK);
break;
case OLE_WARN_DELETE_DATA:
break;
case OLE_WAIT_FOR_RELEASE:
if (!fWait)
{
pDoc->cWait++;
os=OLE_OK;
break;
}
else
{
pObj->fRelease=FALSE;
FOLEReleaseWait(FALSE, pDoc, pObj);
os=OleQueryReleaseError(pObj->pObj);
}
if (OLE_OK==os)
break;
//FALL THROUGH if OLE_OK!=OleQueryReleaseError.
//This is not a wonderful way to handle errors for end users.
default:
#ifdef DEBUG
orm=OleQueryReleaseMethod(pObj->pObj);
wsprintf(szMsg, PSZOLE(IDS_OLEERRORMSG), orm, os);
OutputDebugString(szMsg);
OutputDebugString("\n\r");
#endif
break;
}
return os;
}